/*
    The I Ching (the Book of Changes) plasmoid.
    Copyright (C) 2002-2009 Jean Pierre Charalambos.
    TrigramSelector Jorge Andrés Martínez

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/
#include "trigramselector.h"
#include "trigram.h"

//QT
#include <QGraphicsSceneEvent>
#include <QPainter>
#include <QString>
#include <QGraphicsWidget>

//Stdlibs
#include <math.h>
#include <cstdlib>
#include <ctime>

using namespace std;

/**
* Clase para mostrar un tablero del cual se selecciona un trigrama por medio del puntero.
* Se debe incluir en un QGraphicsWidget/layout ya que es un elemento gráfico.
*
**/
TrigramSelector::TrigramSelector ( QGraphicsWidget* parent ) : QGraphicsWidget ( parent ) {
  srand((unsigned)time(0));
  
  trigamsSvg = new Plasma::Svg();
  trigamsSvg->setImagePath("/usr/lib/kde4/plasma_applet_iching/IchingSelector.svg");
  trigamsSvg->setContainsMultipleImages(true);
  selected = "li";

  int xborder = 50;
  
  //Ubicación de los elementos en el svg desplazados el borde en el que se encuentra ubicado el selector
  liBounds      = QRectF( (QPointF(70 +xborder,0  )), (QPointF(130+xborder,65 )));
  sunBounds     = QRectF( (QPointF(130+xborder,20 )), (QPointF(180+xborder,70 )));
  chienBounds   = QRectF( (QPointF(135+xborder,70 )), (QPointF(200+xborder,130)));
  tuiBounds     = QRectF( (QPointF(130+xborder,130)), (QPointF(180+xborder,180)));
  kanBounds     = QRectF( (QPointF(70 +xborder,135)), (QPointF(130+xborder,200)));
  chenBounds    = QRectF( (QPointF(15 +xborder,125)), (QPointF(70 +xborder,180)));
  kunBounds     = QRectF( (QPointF(10 +xborder,65 )), (QPointF(50 +xborder,125)));
  kenBounds     = QRectF( (QPointF(20 +xborder,20 )), (QPointF(75 +xborder,70 )));
  taijituBounds = QRectF( (QPointF(75 +xborder,70 )), (QPointF(130+xborder,130)));
  
}

/**
*  Este metodo se ejecuta cuando se hace click encima del selector,
*  se encarga de cambiar el trigrama seleccionado dependiendo del lugar en el que se haga click,
*  obteniendo elemento seleccionado del método positionToTrigram.
*  Emite la señal textChanged(QString)
**/
void TrigramSelector::mousePressEvent(QGraphicsSceneMouseEvent *event){
    QString elemName = positionToTrigram( event->pos() );
    if(elemName.compare("")){
      selected = elemName;
    }
    emit textChanged(selected);
    update();
}

/**
*  Se encarga de pintar el selector cada vez que sea necesario, este método se dispara por el método mousePressEvent
*  al seleccionar un trigrama.
**/
void TrigramSelector::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
  
    QPointF pos = trigramToPosition(selected);
    QRectF size = getTrigramDimentions(selected);
    
    //pintar el tablero
    trigamsSvg->paint(painter,50,0, 200, 200,"");
    
    //pintar la seleccion
    QRadialGradient shade(size.x() + size.width()/2, size.y() + size.height()/2, 100);
    shade.setColorAt(0, Qt::lightGray);
    shade.setColorAt(1, Qt::transparent);
    QBrush brush = QBrush(shade);
    painter->setBrush(brush);
    QPen pen = QPen();
    pen.setBrush(brush);
    pen.setWidth(6);
    painter->setPen(pen);
    painter->drawLine(size.x(),size.y(),size.x(), size.y() + size.height());
    painter->drawLine(size.x(),size.y(),size.x() + size.width(), size.y());
    painter->drawLine(size.x() + size.width(),size.y(),size.x() + size.width(), size.y() + size.height());
    painter->drawLine(size.x(),size.y() + size.height(),size.x() + size.width(), size.y() + size.height());
}

/**
* Este método retorna el trigrama que se encuentra en una posicion dada,
* un trigrama aleatorio si se hace click en el taijitu,
* o cadena vacia si la posicion no esta en ningun elemento.
*
* @param pos posicion sobre la que se quiere verificar a que trigrama corresponde.
* @return nombre del trigrama en esa posición o cadena vacia si no hay nada.
*
**/
QString TrigramSelector::positionToTrigram(QPointF pos){
  
  if(liBounds.contains(pos)){
    return "li";
  }else if(sunBounds.contains(pos)){
    return "sun";
  }else if(chienBounds.contains(pos)){
    return "ch'ien";
  }else if(tuiBounds.contains(pos)){
    return "tui";
  }else if(kanBounds.contains(pos)){
    return "kan";
  }else if(chenBounds.contains(pos)){
    return "chen";
  }else if(kunBounds.contains(pos)){
    return "kun";
  }else if(kenBounds.contains(pos)){
    return "ken";
  }else if(taijituBounds.contains(pos)){
    int triRand = (int)(rand()%8+1);
    switch(triRand){
      case 1:{
	return "li";break;}
      case 2:{
	return "sun";break;}
      case 3:{
	return "ch'ien";break;}
      case 4:{
	return "tui";break;}
      case 5:{
	return "kan";break;}
      case 6:{
	return "chen";break;}
      case 7:{
	return "kun";break;}
      case 8:{
	return "ken";break;}
      default:{
	return "li";break;}
    }
  }else{
    return "";
  }
}

/**
* Metodo que retorna la posicion de un trigrama dado su nombre.
*	Nota; obtener del svg para permitir personalizarlo
* @param name nombre del trigrama del que se quiere saber su posicion
* @return punto central del trigrama con ese nombre.
*
**/
QPointF TrigramSelector::trigramToPosition(QString name){
  int x = 0;
  int y = 0;
  if(QString::compare(name, "li", Qt::CaseInsensitive) == 0){
    x = liBounds.x()+liBounds.width()/2;
    y = liBounds.y()+liBounds.height()/2;
  }else if(QString::compare(name, "sun", Qt::CaseInsensitive) == 0){
    x = sunBounds.x()+sunBounds.width()/2;
    y = sunBounds.y()+sunBounds.height()/2;
  }else if(QString::compare(name, "ch'ien", Qt::CaseInsensitive) == 0){
    x = chienBounds.x()+chienBounds.width()/2;
    y = chienBounds.y()+chienBounds.height()/2;
  }else if(QString::compare(name, "tui", Qt::CaseInsensitive) == 0){
    x = tuiBounds.x()+tuiBounds.width()/2;
    y = tuiBounds.y()+tuiBounds.height()/2;
  }else if(QString::compare(name, "kan", Qt::CaseInsensitive) == 0){
    x = kanBounds.x()+kanBounds.width()/2;
    y = kanBounds.y()+kanBounds.height()/2;
  }else if(QString::compare(name, "chen", Qt::CaseInsensitive) == 0){
    x = chenBounds.x()+chenBounds.width()/2;
    y = chenBounds.y()+chenBounds.height()/2;
  }else if(QString::compare(name, "kun", Qt::CaseInsensitive) == 0){
    x = kunBounds.x()+kunBounds.width()/2;
    y = kunBounds.y()+kunBounds.height()/2;
  }else if(QString::compare(name, "ken", Qt::CaseInsensitive) == 0){
    x = kenBounds.x()+kenBounds.width()/2;
    y = kenBounds.y()+kenBounds.height()/2;
  }
    return QPointF(x,y);
}

/**
* Retorna el bounding rect del elemento con el nombre indicado. o un rectangulo longitudes 0 si no existe ese trigrama.
* @param name nombre del que se quiere obtener el bounding rect.
* @return rectangulo envolvente del trigrama.
*
**/
QRectF TrigramSelector::getTrigramDimentions(QString name){

  if(QString::compare(name, "li", Qt::CaseInsensitive) == 0){
    return liBounds;
  }else if(QString::compare(name, "sun", Qt::CaseInsensitive) == 0){
    return sunBounds;
  }else if(QString::compare(name, "ch'ien", Qt::CaseInsensitive) == 0){
    return chienBounds;
  }else if(QString::compare(name, "tui", Qt::CaseInsensitive) == 0){
    return tuiBounds;
  }else if(QString::compare(name, "kan", Qt::CaseInsensitive) == 0){
    return kanBounds;
  }else if(QString::compare(name, "chen", Qt::CaseInsensitive) == 0){
    return chenBounds;
  }else if(QString::compare(name, "kun", Qt::CaseInsensitive) == 0){
    return kunBounds;
  }else if(QString::compare(name, "ken", Qt::CaseInsensitive) == 0){
    return kenBounds;
  }
    return QRectF(0,0,0,0);
}

/**
* Retorna el nombre del trigrama actualmente seleccionado.
*
**/
QString TrigramSelector::getSelected(){
  return selected;
}